#include "kvstore2pcsystem.h"
#include "GLOBAL.h"
#include <iostream>
#include <algorithm>
#include <getopt.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fstream>
#include <sstream>
using namespace std;
/*
构造函数：解析长指令，获取配置文件的文件名
init：解析配置文件的内容，根据文件指定结点类型赋值kvstore2pcsystem参数：mode
*/
kvstore2pcsystem::kvstore2pcsystem(int argc, char* argv[]) {
    char *string_ = new char[2];
    conf = new char[255];
    mode = MODE_INVALID;
    static struct option long_options[]{
        {"config_path", required_argument, NULL, 1},
    };
    int opt;
    int option_index = 0;
    if((opt = getopt_long(argc, argv, string_, long_options, &option_index)) != -1){
        cout << "Get conf ：optarg = " << optarg << endl;
        strcpy(conf, optarg);
    }else {
        cout << "input error! please input correct config_path" << endl;
    }
    init();
}
bool kvstore2pcsystem::readConf_2PC(std::vector<NodeInfo> & p, NodeInfo & c)
{
  std::fstream conf_file;
  conf_file.open(conf); 
  if (!conf_file.is_open())
  {
    return false;
  }

  // read
  while (!conf_file.eof())
  {
    std::string buf;
    getline(conf_file, buf);
    // Annotate
    if ('!' == buf[0])
    {
      continue;
    }

    // get the mode
    if(buf.find("mode") != std::string::npos) {
      if(buf.find("coordinator") != std::string::npos) {
        mode = MODE_C;
      } else if(buf.find("participant") != std::string::npos) {
        mode = MODE_P;
      } else {
        mode = MODE_INVALID;
        return false;
      }
    }
    // if((mode != MODE_C)&&(mode != MODE_P)){
    //   return false;
    // } 
    
    if(buf.find("coordinator_info") != std::string::npos) {
      
      size_t pos = buf.find("coordinator_info");
      buf = buf.substr(pos + 16);
      
      buf.erase(std::remove(buf.begin(), buf.end(), ' '), buf.end());

      pos = buf.find(":");
      if(pos == std::string::npos) {
        return false;
      }
      else {
        c.add = buf.substr(0, pos);
        c.port = strtol((buf.substr(pos + 1)).c_str(), nullptr, 10);
      }
    } 
    
    else if(buf.find("participant_info") != std::string::npos) {
      NodeInfo tmp;
      size_t pos = buf.find("participant_info");
      buf = buf.substr(pos + 16);
      buf.erase(remove(buf.begin(), buf.end(), ' '), buf.end());

      pos = buf.find(":");
      if(pos == std::string::npos) {
        return false;
      }
      else {
        tmp.add = buf.substr(0, pos);
        tmp.port = strtol((buf.substr(pos + 1)).c_str(), nullptr, 10);
        p.push_back(tmp);
      }
    }
  }

  return true;
}
bool kvstore2pcsystem::readConf_RAFT(std::vector<NodeInfo> & p, NodeInfo & c, std::vector<NodeInfo> & f)
{
  std::fstream conf_file;
  conf_file.open(conf); 
  if (!conf_file.is_open())
  {
    return false;
  }

  // read
  int index = 0;
  while (!conf_file.eof())
  {
    std::string buf;
    getline(conf_file, buf);
    // Annotate
    if ('!' == buf[0])
    {
      continue;
    }
    
    if(buf.find("follower_info") != std::string::npos) {
      mode = MODE_RAFT;
      NodeInfo tmp;
      size_t pos = buf.find("follower_info");
      buf = buf.substr(pos + 13);
      buf.erase(remove(buf.begin(), buf.end(), ' '), buf.end());

      pos = buf.find(":");
      if(++index == 1){  // only one follower
        if(pos == std::string::npos) {
          return false;
        }
        else {
          tmp.add = buf.substr(0, pos);
          tmp.port = strtol((buf.substr(pos + 1)).c_str(), nullptr, 10);
          p.push_back(tmp);
        }
      }
      if(pos == std::string::npos) {
          return false;
        }
      else {
        tmp.add = buf.substr(0, pos);
        tmp.port = strtol((buf.substr(pos + 1)).c_str(), nullptr, 10);
        // if(tmp.port == pinfo[0].port)
        //   continue;
        f.push_back(tmp);
      }
    } 
    
  }

  return true;
}
void kvstore2pcsystem::showInfo(std::vector<NodeInfo>  p, NodeInfo  c, std::vector<NodeInfo> & f)
{
  if(mode == MODE_C) {
    std::cout << "COORDINATOR" << std::endl;
  } else if ( mode == MODE_P ) {
    std::cout << "PARTICIPANT" << std::endl;
  } else if ( mode == MODE_RAFT ) {
    std::cout << "RAFT" << std::endl;
  } else {
    std::cout << "INVALID" << std::endl;
  }

  std::cout << "C: " << c.add << ":" << c.port << std::endl;

  for(auto entry : p) 
  {
    std::cout << "P: " << entry.add << ":" << entry.port << std::endl;
  }
  if ( mode == MODE_RAFT ){
    for(auto entry : f) 
    {
      std::cout << "f: " << entry.add << ":" << entry.port << std::endl;
    }
  }
}

void kvstore2pcsystem::init() {
    struct stat s;
    // stat(fln ,&s)构造stat结构体变量，用于存储文件的状态信息，stat函数的返回值为0表示获取状态信息成功，非零值表示失败
    // S_IFREG是一个宏定义，用于表示普通文件的类型
    if (stat(conf ,&s)==0 && s.st_mode & S_IFREG) {
        fstream input(conf);
        /**************** 完成init方法，解析配置文件 ****************/
        // begin

        if( !readConf_2PC(pinfo, cinfo) ) {
            std::cout << "> NOT 2PC MODE. " << std::endl;
        }
        else if( !readConf_RAFT(pinfo, cinfo, finfo) ) {
            std::cout << "> NOT RAFT MODE. " << std::endl;
        }

        if( mode == MODE_INVALID ) {
            std::cout << "> ERROR: UNDEFINE THE TYPE OF THE NODE. " << std::endl;
            return ;
        }

        // end
        if(G_DE_BUG) {
            std::cout << "> SHWOINFO " <<std::endl;
            showInfo(pinfo, cinfo, finfo);
        }
    }else {
        cout << "input error! please input correct config_path !!!" << endl;
    }

}
kvstore2pcsystem::~kvstore2pcsystem() {
}

